﻿/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace DaveSexton.DocProject.Sandcastle.Configuration
{
	internal sealed class PresentationImporter
	{
		#region Public Properties
		public ICollection<string> Warnings
		{
			get
			{
				return warnings.AsReadOnly();
			}
		}
		#endregion

		#region Private / Protected
		private readonly IDocProject project, importFrom;
		private readonly Presentation presentation, importFromPresentation;
		private readonly string root, relativeRoot, sourcePresentationPath, targetPresentationPath, settingsPath, topics, targetSchemas;
		private readonly bool importFromDifferentPresentationStyle;
		private readonly SandcastleSettings importFromSettings;
		private readonly Version sandcastleVersion, docProjectVersion, importFromSandcastleVersion, importFromDocProjectVersion;
		private readonly DirectoryCopier copier = new DirectoryCopier();
		private readonly List<string> warnings = new List<string>();
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="PresentationImporter" /> class.
		/// </summary>
		public PresentationImporter(IDocProject project, Presentation presentation, IDocProject importFrom)
		{
			if (project == null)
				throw new ArgumentNullException("project");

			if (presentation == null)
				throw new ArgumentNullException("presentation");

			sourcePresentationPath = System.IO.Path.Combine(SandcastleBuildEngineProvider.Paths.Presentation, presentation.Path);

			if (!System.IO.Directory.Exists(sourcePresentationPath))
				throw new System.IO.DirectoryNotFoundException(string.Format(System.Globalization.CultureInfo.CurrentCulture,
					Resources.Errors.PresentationDoesNotExist, sourcePresentationPath));

			relativeRoot = SandcastleBuildEngineProvider.ProjectPaths.RelativeHelpRoot;
			root = System.IO.Path.Combine(project.Directory, relativeRoot);

			settingsPath = System.IO.Path.Combine(root, SandcastleBuildEngineProvider.ProjectPaths.RelativeSettingsPath);
			topics = System.IO.Path.Combine(root, SandcastleBuildEngineProvider.ProjectPaths.RelativeTopicsPath);
			targetPresentationPath = System.IO.Path.Combine(root, SandcastleBuildEngineProvider.ProjectPaths.Presentation);
			targetSchemas = System.IO.Path.Combine(root, SandcastleBuildEngineProvider.ProjectPaths.RelativeSchemasPath);

			this.project = project;
			this.presentation = presentation;
			this.importFrom = importFrom;		// allow null

			if (importFrom != null)
			{
				importFromSettings = TryGetSettings(warnings, importFrom);
				importFromPresentation = Presentation.GetPresentation(importFrom);

				if (importFromPresentation == null || !string.Equals(importFromPresentation.Path, presentation.Path, StringComparison.OrdinalIgnoreCase))
				{
					importFromDifferentPresentationStyle = true;

					warnings.Add(string.Format(System.Globalization.CultureInfo.CurrentCulture, 
						Resources.Text.WarningImportFromDifferentPresentationStyle, importFromPresentation.Path, presentation.Path));
				}

				GetVersions(project, out sandcastleVersion, out docProjectVersion);
				GetVersions(importFrom, out importFromSandcastleVersion, out importFromDocProjectVersion);

				if (importFromSandcastleVersion != sandcastleVersion)
					warnings.Add(string.Format(System.Globalization.CultureInfo.CurrentCulture,
						Resources.Text.WarningDifferentSandcastleVersions, importFromSandcastleVersion, sandcastleVersion));

				if (importFromDocProjectVersion != docProjectVersion)
					warnings.Add(string.Format(System.Globalization.CultureInfo.CurrentCulture,
						Resources.Text.WarningDifferentDocProjectVersions, importFromDocProjectVersion, docProjectVersion));
			}
		}
		#endregion

		#region Methods
		public static bool ShouldImportPresentationContent(IDocProject project, Presentation presentation)
		{
			if (project == null)
				throw new ArgumentNullException("project");

			if (presentation == null)
				throw new ArgumentNullException("presentation");

			IDocProject importFrom = presentation.ImportFrom;

			if (importFrom == null)
				return false;

			Presentation importFromPresentation = Presentation.GetPresentation(importFrom);

			return importFromPresentation != null
				&& string.Equals(importFromPresentation.Path, presentation.Path, StringComparison.OrdinalIgnoreCase)
				&& string.Equals(SandcastleProjectOptions.GetSandcastleVersion(importFrom),
					SandcastleProjectOptions.GetSandcastleVersion(project), StringComparison.OrdinalIgnoreCase);
		}

		[System.Diagnostics.DebuggerHidden]
		private static void GetVersions(IDocProject project, out Version sandcastleVersion, out Version docProjectVersion)
		{
			sandcastleVersion = null;
			docProjectVersion = null;

			try
			{
				string version = SandcastleProjectOptions.GetSandcastleVersion(project);

				if (!string.IsNullOrEmpty(version))
					sandcastleVersion = new Version(version);
			}
			catch (ArgumentException) { }
			catch (FormatException) { }
			catch (OverflowException) { }

			try
			{
				string version = DocProjectOptions.GetDocProjectVersion(project);

				if (!string.IsNullOrEmpty(version))
					docProjectVersion = new Version(version);
			}
			catch (ArgumentException) { }
			catch (FormatException) { }
			catch (OverflowException) { }

			if (sandcastleVersion == null)
				sandcastleVersion = new Version(0, 0, 0, 0);

			if (docProjectVersion == null)
				docProjectVersion = new Version(0, 0, 0, 0);
		}

		private static void AddWarning(List<string> warnings, Exception ex, string message, params object[] messageArgs)
		{
			if (messageArgs != null)
				message = string.Format(System.Globalization.CultureInfo.CurrentCulture, message, messageArgs);

			Log.Exception(ex, message);

			if (ex != null)
				message += Environment.NewLine + "Reason: " + ex.Message;

			warnings.Add(message);
		}

		[System.Diagnostics.DebuggerHidden]
		private static bool TryCopyFile(List<string> warnings, string source, string target, string warningWhenFailed, params object[] warningFormatArgs)
		{
			try
			{
				System.IO.File.Copy(source, target, true);
				return true;
			}
			catch (System.IO.FileNotFoundException ex)
			{
				AddWarning(warnings, ex, string.Format(System.Globalization.CultureInfo.CurrentCulture, warningWhenFailed, warningFormatArgs));
			}
			catch (System.IO.DirectoryNotFoundException ex)
			{
				AddWarning(warnings, ex, string.Format(System.Globalization.CultureInfo.CurrentCulture, warningWhenFailed, warningFormatArgs));
			}
			catch (System.UnauthorizedAccessException ex)
			{
				AddWarning(warnings, ex, string.Format(System.Globalization.CultureInfo.CurrentCulture, warningWhenFailed, warningFormatArgs));
			}
			catch (System.ArgumentException ex)
			{
				AddWarning(warnings, ex, string.Format(System.Globalization.CultureInfo.CurrentCulture, warningWhenFailed, warningFormatArgs));
			}
			catch (System.IO.IOException ex)
			{
				AddWarning(warnings, ex, string.Format(System.Globalization.CultureInfo.CurrentCulture, warningWhenFailed, warningFormatArgs));
			}

			return false;
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
		private static SandcastleSettings TryGetSettings(List<string> warnings, IDocProject importFromProject)
		{
			try
			{
				SandcastleBuildEngine engine = BuildController.GetEngineForProject(importFromProject) as SandcastleBuildEngine;

				if (engine == null)
					AddWarning(warnings, null, Resources.Errors.CannotGetBuildEngineForProject);
				else
				{
					SandcastleSettings settings = engine.Settings;

					if (settings == null)
						AddWarning(warnings, null, Resources.Errors.CannotGetBuildSettingsForProject);

					return settings;
				}
			}
			catch (Exception ex)
			{
				AddWarning(warnings, ex, Resources.Errors.CannotGetBuildSettingsForProject);
			}

			return null;
		}

		private static int ImportFiles(IDocProject project, string sourcePath, string targetPath, string searchPattern, bool recursive, bool refreshTarget)
		{
			int count = 0;
			Uri sourceUri = new Uri(PathFormat.EnsureDirectory(sourcePath));

			foreach (string file in System.IO.Directory.GetFiles(sourcePath, searchPattern,
				(recursive) ? System.IO.SearchOption.AllDirectories : System.IO.SearchOption.TopDirectoryOnly))
			{
				Uri fileUri = new Uri(file);

				string relativeFile = System.Web.HttpUtility.UrlDecode(sourceUri.MakeRelativeUri(fileUri).ToString());
				string target = System.IO.Path.Combine(targetPath, relativeFile);
				string targetFolder = System.IO.Path.GetDirectoryName(target);

				if (!System.IO.Directory.Exists(targetFolder))
					System.IO.Directory.CreateDirectory(targetFolder);

				System.IO.File.Copy(file, target, true);

				count++;
			}

			if (refreshTarget)
				project.GetFolder(targetPath).Refresh();

			return count;
		}

		public void Import()
		{
			if (!System.IO.Directory.Exists(targetPresentationPath))
				// NOTE: This folder must exist before files are imported.  When an item is shown in Solution Explorer using project.GetItem(name).Show()
				// it frees the UI thread for a moment and VS may query the stauts of a command button on the Sandcastle command bar, which causes 
				// the SandcastleSettings for the new project to be created, and that relies on the presentation path being set; but the presentation 
				// path is calcaulated dynamically depending upon whether the relative presentation folder exists, so it must be created before any other 
				// code is executed.
				System.IO.Directory.CreateDirectory(targetPresentationPath);

			if (importFrom != null)
			{
				// NOTE: External sources are not imported by the following methods since they are imported automatically by the
				// last step of the New Project Wizard.  The import settings wizard step assigns the external sources to that step automatically.

				if (importFrom.Provider is SandcastleBuildEngineProvider)
					// NOTE: This method also imports the base DocProjectOptions
					// NOTE: The project's provider must do the import, not the importFrom provider.
					((SandcastleBuildEngineProvider) project.Provider).ImportOptions(importFrom, project);
				else
					DocProjectOptions.ImportOptions(importFrom, project, false);
			}

			// Import resources before the included presentation folders are imported so that the resources are included as project items
			// without having to explicitly call Show, which will automatically expand the folder node when it shouldn't be expanded.
			ImportResources();

			ImportArt();

			ImportTopics();

			ImportContent();

			ImportSchemas();

			ImportSharedPresentation();

			ImportExternalXmlDocumentationFiles();

			ImportConfigurationFiles();
		}

		private void ImportResources()
		{
			if (!System.IO.Directory.Exists(settingsPath))
				System.IO.Directory.CreateDirectory(settingsPath);

			ImportHelpCompilerProjectFiles();
			ImportSettingsFiles();
			ImportCustomStyleSheets();

			project.GetFolder(settingsPath).Show();
		}

		private void ImportHelpCompilerProjectFiles()
		{
			string projectConfigDirectory = System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultProjectConfigurationDirectory);

			if (!System.IO.Directory.Exists(projectConfigDirectory))
				System.IO.Directory.CreateDirectory(projectConfigDirectory);

			string help1xProjectConfig = System.IO.Path.Combine(projectConfigDirectory, SandcastleSettings.DefaultHelp1xProjectConfigFileName);
			string help2xProjectConfig = System.IO.Path.Combine(projectConfigDirectory, SandcastleSettings.DefaultHelp2xProjectConfigFileName);

			string targetHelp2xFiles = System.IO.Path.Combine(root, SandcastleSettings.DefaultHelp2xFilesCollectionFileName);
			string targetIndex_a = System.IO.Path.Combine(root, SandcastleSettings.DefaultHelp2xAssociativeIndexFileName);
			string targetIndex_b = System.IO.Path.Combine(root, SandcastleSettings.DefaultHelp2xDynamicLinkIndexFileName);
			string targetIndex_f = System.IO.Path.Combine(root, SandcastleSettings.DefaultHelp2xContextSensitiveIndexFileName);
			string targetIndex_k = System.IO.Path.Combine(root, SandcastleSettings.DefaultHelp2xKeywordIndexFileName);
			string targetIndex_s = System.IO.Path.Combine(root, SandcastleSettings.DefaultHelp2xSearchWindowIndexFileName);
			string targetIndex_n = System.IO.Path.Combine(root, SandcastleSettings.DefaultHelp2xNamedUrlIndexFileName);

			bool import1xDefault = true, import2xDefault = true;

			if (importFrom != null)
			{
				if (importFromSettings != null)
				{
					import1xDefault = !TryCopyFile(warnings, importFromSettings.Help1xProjectConfigFile, help1xProjectConfig, Resources.Errors.CannotImportHelp1xProject);
					import2xDefault = !TryCopyFile(warnings, importFromSettings.Help2xProjectConfigFile, help2xProjectConfig, Resources.Errors.CannotImportHelp2xProject);

					TryCopyFile(warnings, importFromSettings.Help2xFilesCollectionFile, targetHelp2xFiles, Resources.Errors.CannotImportHelp2xCollectionFile);
					TryCopyFile(warnings, importFromSettings.Help2xAssociativeIndexFile, targetIndex_a, Resources.Errors.CannotImportHelp2xAIndex);
					TryCopyFile(warnings, importFromSettings.Help2xDynamicLinkIndexFile, targetIndex_b, Resources.Errors.CannotImportHelp2xBIndex);
					TryCopyFile(warnings, importFromSettings.Help2xContextSensitiveIndexFile, targetIndex_f, Resources.Errors.CannotImportHelp2xFIndex);
					TryCopyFile(warnings, importFromSettings.Help2xKeywordIndexFile, targetIndex_k, Resources.Errors.CannotImportHelp2xKIndex);
					TryCopyFile(warnings, importFromSettings.Help2xSearchWindowIndexFile, targetIndex_s, Resources.Errors.CannotImportHelp2xSIndex);
					TryCopyFile(warnings, importFromSettings.Help2xNamedUrlIndexFile, targetIndex_n, Resources.Errors.CannotImportHelp2xNIndex);
				}
			}

			if (import1xDefault)
				System.IO.File.WriteAllText(help1xProjectConfig, Resources.Documents.Help1xProjectConfig, Encoding.UTF8);

			if (import2xDefault)
				System.IO.File.WriteAllText(help2xProjectConfig, Resources.Documents.Help2xProjectConfig, Encoding.UTF8);
		}

		private void ImportSettingsFiles()
		{
			List<string[]> files = new List<string[]>
			{
				new[] { System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultConceptualArtMapFileName), Resources.Documents.ConceptualArtMap }, 
				new[] { System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultConceptualSnippetsFileName), Resources.Documents.ConceptualSnippets }, 
				new[] { System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultConceptualProjectMetadataFileName), Resources.Documents.ConceptualProject }, 
				new[] { System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultConceptualVersionMetadataFileName), Resources.Documents.ConceptualVersion }, 
				new[] { System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultTokensFileName), Resources.Documents.Tokens }, 
				new[] { System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultGlobalMetadataFileName), Resources.Documents.GlobalMetadata }, 
				new[] { System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultLinksFileName), Resources.Documents.Links }, 
				new[] { System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultBibliographyFileName), Resources.Documents.Bibliography }, 
			};

			foreach (string[] data in files)
			{
				string target = data[0];
				string defaultContents = data[1];

				bool writeDefault = true;

				if (importFromSettings != null)
				{
					string name = System.IO.Path.GetFileName(target);

					string source = System.IO.Path.Combine(System.IO.Path.Combine(
						importFromSettings.TargetDirectory, SandcastleBuildEngineProvider.ProjectPaths.RelativeSettingsPath),
						name);

					writeDefault = !TryCopyFile(warnings, source, target, Resources.Errors.CannotImportSettingsFile, name);
				}

				if (writeDefault)
					System.IO.File.WriteAllText(target, defaultContents);
			}
		}

		private void ImportCustomStyleSheets()
		{
			string stylesFolder = presentation.CascadingStyleSheetsDirectory;
			string stylesFullPath = System.IO.Path.Combine(root, stylesFolder);

			if (!System.IO.Directory.Exists(stylesFullPath))
				System.IO.Directory.CreateDirectory(stylesFullPath);

			string topicDesignerStyleSheet = System.IO.Path.Combine(stylesFullPath, Presentation.TopicDesignerStyleSheetFileName);

			bool writeDefault = true;

			if (importFromSettings != null)
			{
				string source = System.IO.Path.Combine(System.IO.Path.Combine(
					importFromSettings.TargetDirectory, importFromSettings.Presentation.CascadingStyleSheetsDirectory),
					Presentation.TopicDesignerStyleSheetFileName);

				writeDefault = !TryCopyFile(warnings, source, topicDesignerStyleSheet, Resources.Errors.CannotImportTopicDesignerStyleSheet);
			}

			if (writeDefault)
				System.IO.File.WriteAllText(topicDesignerStyleSheet, Resources.StyleSheets.TopicDesigner);
		}

		private void ImportArt()
		{
			if (importFromSettings != null)
			{
				string source = System.IO.Path.Combine(importFromSettings.TargetDirectory, importFromPresentation.MediaDirectory);
				string target = System.IO.Path.Combine(root, presentation.MediaDirectory);

				if (System.IO.Directory.Exists(source))
				{
					try
					{
						copier.CopyDirectory(source, target);
					}
					catch (System.IO.DirectoryNotFoundException) { }

					project.GetFolder(target).Refresh();
				}
			}
		}

		private void ImportTopics()
		{
			int count = 0;

			if (importFromSettings != null)
			{
				try
				{
					if (System.IO.Directory.Exists(importFromSettings.TopicsHtmlDirectory))
					{
						// NOTE: The HTML files must be imported first since they are contained in a subdirectory.  The ImportTopics method 
						// creates a project item for each individual MAML topic as they're copied, which means that the Topics folder is included
						// as a project item automatically.  Since it's already included, the code that explicitly adds it as a folder does not 
						// seem to affect excluded subdirectories unless the Topics folder itself is also currently excluded.
						count += ImportFiles(project, importFromSettings.TopicsHtmlDirectory, System.IO.Path.Combine(topics, SandcastleSettings.DefaultTopicsHtmlFolderName),
							"*.htm?", true, false);
					}
				}
				catch (System.IO.DirectoryNotFoundException) { }

				int conceptualCount = 0;
				string topicsFile = importFromSettings.TopicsFile;

				Dictionary<string, string> titles = LegacyGetTopicTitles(topicsFile);

				SystemPath source = new SystemPath(importFromSettings.TopicsDirectory, false, true);

				if (source.Exists)
				{
					conceptualCount += ImportTopics(titles, source, topics, TopicManagement.ConceptualTopicFileManager.TopicFileExtension);
					conceptualCount += ImportTopics(titles, source, topics, TopicManagement.ConceptualTopicFileManager.TopicFileGeneralExtension);
				}

				count += conceptualCount;

				if (conceptualCount > 0 && System.IO.File.Exists(topicsFile))
				{
					string target = System.IO.Path.Combine(settingsPath, SandcastleSettings.DefaultTopicsFileName);

					if (TryCopyFile(warnings, topicsFile, target, Resources.Errors.CannotImportTopicsFile, topicsFile))
					{
						XmlDocument document = new XmlDocument();
						document.PreserveWhitespace = true;
						document.Load(target);

						foreach (XmlElement element in document.SelectNodes("//topic"))
						{
							XmlAttribute file = element.Attributes["file"];
							if (file != null)
							{
								string value = file.Value;

								if (!string.IsNullOrEmpty(value))
								{
									XmlAttribute id = element.Attributes["id"];

									bool updatedValue = false;

									if (id != null)
									{
										string guid = id.Value;

										if (!string.IsNullOrEmpty(guid))
										{
											XmlAttribute titleAttribute = element.Attributes["title"];
											
											if (titleAttribute != null)
												element.Attributes.Remove(titleAttribute);

											// NOTE: The titles dictionary now contains the file names that were used by the import procedure instead
											// of the titles that were originally passed to it.
											if (titles.ContainsKey(guid))
											{
												string newFile = titles[guid];

												if (!string.IsNullOrEmpty(newFile) && !string.Equals(newFile, guid, StringComparison.OrdinalIgnoreCase))
												// NOTE: The file name was changed during the import so it must be updated in the topics.xml file as well.
												{
													value = newFile;
													updatedValue = true;
												}
											}
										}
									}

									if (!updatedValue && (string.IsNullOrEmpty(System.IO.Path.GetExtension(value))
										|| value.EndsWith(TopicManagement.ConceptualTopicFileManager.TopicFileGeneralExtension, StringComparison.OrdinalIgnoreCase)))
										// NOTE: Topic files with an .xml extension are automatically converted to .aml topics during the import, so the topics.xml
										// file must be updated as well.
										// NOTE: ChangeExtension will add the extension if one doesn't already exist
										value = System.IO.Path.ChangeExtension(value, TopicManagement.ConceptualTopicFileManager.TopicFileExtension);

									file.Value = value;
								}
							}
						}

						document.Save(target);

						project.GetItem(target).Show();
					}
				}

				if (count == 0)
					warnings.Add(Resources.Text.WarningNoTopicsImported);
			}

			project.GetFolder(topics).Show();
		}

		/// <remarks>
		/// As of 1.11.0 RC the topics.xml file no longer stores conceptual topic titles except 
		/// for container nodes and HTML files only.  The titls are stored in companion files 
		/// that are known to the method that imports the topics, so generating an index of 
		/// titles from the topics.xml file is only necessary when importing topics that 
		/// have a GUID file name, do not have companion files and have a corresponding entry
		/// in a legacy topics.xml file; e.g., any project created from 1.9 to 1.10.1 RC.
		/// </remarks>
		private static Dictionary<string, string> LegacyGetTopicTitles(string topicsFile)
		{
			Dictionary<string, string> titles = new Dictionary<string, string>(0, StringComparer.OrdinalIgnoreCase);

			if (!string.IsNullOrEmpty(topicsFile))
			{
				try
				{
					XmlDocument document = new XmlDocument();
					document.Load(topicsFile);

					foreach (XmlElement topic in document.SelectNodes("//topic"))
					{
						XmlAttribute title = topic.Attributes["title"];
						XmlAttribute id = topic.Attributes["id"];
						XmlAttribute file = topic.Attributes["file"];

						if (id != null && title != null && file != null
							&& (file.Value.EndsWith(TopicManagement.ConceptualTopicFileManager.TopicFileExtension, StringComparison.OrdinalIgnoreCase)
								|| file.Value.EndsWith(TopicManagement.ConceptualTopicFileManager.TopicFileGeneralExtension, StringComparison.OrdinalIgnoreCase)
								|| string.Equals(file.Value, id.Value, StringComparison.OrdinalIgnoreCase)))
						{
							titles.Add(id.Value, title.Value);
						}
					}
				}
				catch (System.IO.IOException) { }
				catch (ArgumentException) { }
				catch (XmlException) { }
			}

			return titles;
		}

		private int ImportTopics(Dictionary<string, string> legacyTopicTitles, SystemPath source, string topics, string fileExtension)
		{
			int count = 0;

			try
			{
				foreach (SystemPath file in source.GetFiles("*" + fileExtension, true))
				{
					SystemPath target = new SystemPath(topics, file.RelativeTo(source), false, false);
					SystemPath directory = target.Directory;

					if (!directory.Exists)
						System.IO.Directory.CreateDirectory(directory);

					try
					{
						TopicManagement.ConceptualTopicFileManager.CopyTopicFile(project, file, target, legacyTopicTitles);
						count++;
					}
					catch (System.IO.IOException ex)
					{
						AddWarning(warnings, ex, Resources.Errors.CannotImportTopicFile, file);
					}
					catch (ArgumentException ex)
					{
						AddWarning(warnings, ex, Resources.Errors.CannotImportTopicFile, file);
					}
					catch (UnauthorizedAccessException ex)
					{
						AddWarning(warnings, ex, Resources.Errors.CannotImportTopicFile, file);
					}
					catch (System.Xml.XmlException ex)
					{
						AddWarning(warnings, ex, Resources.Errors.CannotImportTopicFile, file);
					}
				}
			}
			catch (System.IO.DirectoryNotFoundException) { }

			return count;
		}

		private void ImportContent()
		{
			bool overwrite = true;

			if (importFromSettings != null)
			{
				if (importFromDifferentPresentationStyle)
					warnings.Add(Resources.Text.WarningDifferentPresentationFoldersNotImported);
				else if (sandcastleVersion != importFromSandcastleVersion)
					warnings.Add(Resources.Text.WarningDifferentVersionFoldersNotImported);
				else
				{
					string importFromRoot = importFromSettings.TargetDirectory;
					string importFromRootPresentation = System.IO.Path.Combine(importFromRoot, SandcastleBuildEngineProvider.ProjectPaths.Presentation);

					try
					{
						ImportContent(presentation.IncludeFolders, importFromRoot, root, true);
						ImportContent(presentation.IncludePresentationFolders, importFromRootPresentation, targetPresentationPath, true);
						overwrite = false;
					}
					catch (System.IO.IOException) { }
				}
			}

			ImportContent(presentation.IncludeFolders, sourcePresentationPath, root, overwrite);
			ImportContent(presentation.IncludePresentationFolders, sourcePresentationPath, targetPresentationPath, overwrite);
		}

		private void ImportContent(IEnumerable<string> folders, string source, string target, bool overwrite)
		{
			foreach (string folder in folders)
			{
				if (string.IsNullOrEmpty(folder))
					continue;

				string sourcePath = System.IO.Path.Combine(source, folder);
				string targetPath = System.IO.Path.Combine(target, folder);

				if (overwrite || !System.IO.Directory.Exists(targetPath))
				{
					if (!System.IO.Directory.Exists(sourcePath))
						// just create the target path if there is nothing to copy
						System.IO.Directory.CreateDirectory(targetPath);
					else
						copier.CopyDirectory(sourcePath, targetPath);

					project.GetFolder(targetPath).Refresh();
				}
			}
		}

		private void ImportSchemas()
		{
			bool importDefaults = true;

			if (importFromSettings != null)
			{
				try
				{
					string source = System.IO.Path.Combine(importFromSettings.TargetDirectory, SandcastleBuildEngineProvider.ProjectPaths.RelativeSchemasPath);

					ImportFiles(project, source, targetSchemas, "*.xs?", true, true);

					importDefaults = false;
				}
				catch (ArgumentException ex)
				{
					AddWarning(warnings, ex, Resources.Errors.CannotImportSchemas);
				}
				catch (System.IO.IOException ex)
				{
					AddWarning(warnings, ex, Resources.Errors.CannotImportSchemas);
				}
			}

			if (importDefaults)
				ImportFiles(project, SandcastleBuildEngineProvider.Paths.Schemas, targetSchemas, "*.xs?", true, true);
		}

		private void ImportSharedPresentation()
		{
			string targetSharedPresentation = System.IO.Path.Combine(root, SandcastleBuildEngineProvider.ProjectPaths.SharedPresentation);

			bool importDefault = true;

			if (importFrom != null)
			{
				if (importFromDifferentPresentationStyle)
					warnings.Add(Resources.Text.WarningDifferentSharedPresentationImportedFromInstallation);
				else if (sandcastleVersion > importFromSandcastleVersion)
					warnings.Add(Resources.Text.WarningSharedPresentationImportedFromInstallation);
				else
				{
					if (importFromSettings != null)
					{
						string source = System.IO.Path.Combine(importFromSettings.TargetDirectory, SandcastleBuildEngineProvider.ProjectPaths.SharedPresentation);

						try
						{
							copier.CopyDirectory(source, targetSharedPresentation);
							importDefault = false;
						}
						catch (System.IO.DirectoryNotFoundException)
						{
							warnings.Add(Resources.Text.WarningCannotFindSharedPresentationDirectoryInSource);
						}
					}
				}
			}

			if (importDefault)
			{
				string source = SandcastleBuildEngineProvider.Paths.SharedPresentation;

				if (System.IO.Directory.Exists(source))
					copier.CopyDirectory(source, targetSharedPresentation);
			}

			project.GetFolder(targetSharedPresentation).Show();
		}

		private void ImportExternalXmlDocumentationFiles()
		{
			string commentsFolder = SandcastleBuildEngineProvider.ProjectPaths.RelativeCommentsPath;
			string commentsFullPath = System.IO.Path.Combine(root, commentsFolder);

			if (importFromSettings != null)
			{
				string source = System.IO.Path.Combine(importFromSettings.TargetDirectory, commentsFolder);

				if (System.IO.Directory.Exists(source))
				{
					try
					{
						ImportFiles(project, source, commentsFullPath, "*.xml", true, false);
					}
					catch (System.IO.DirectoryNotFoundException) { }
				}
			}

			if (!System.IO.Directory.Exists(commentsFullPath))
				System.IO.Directory.CreateDirectory(commentsFullPath);

			string projectXml = System.IO.Path.Combine(commentsFullPath, SandcastleSettings.DefaultProjectXmlFileName);

			if (!System.IO.File.Exists(projectXml))
				CommentsDocument.CreateProjectFile(TopicManagement.TopicManager.SandcastleRootReferenceProjectId, projectXml);

			project.GetFolder(System.IO.Path.Combine(relativeRoot, commentsFolder)).Show();
		}

		private void ImportConfigurationFiles()
		{
			string targetConfiguration = System.IO.Path.Combine(root, SandcastleBuildEngineProvider.ProjectPaths.Configuration);
			string mRefBuilderConfigFileName = System.IO.Path.GetFileName(SandcastleBuildEngineProvider.Paths.MRefBuilderConfig);
			string targetMRefBuilderConfigFile = System.IO.Path.Combine(targetConfiguration, mRefBuilderConfigFileName);

			System.IO.DirectoryInfo config = new System.IO.DirectoryInfo(targetConfiguration);

			if (!config.Exists)
				config.Create();

			bool importDefaultMRefBuilderConfig = true;

			if (importFromSettings != null)
			// Import MRefBuilder config
			{
				string source = System.IO.Path.Combine(System.IO.Path.Combine(
					importFromSettings.TargetDirectory, SandcastleBuildEngineProvider.ProjectPaths.Configuration),
					mRefBuilderConfigFileName);

				if (System.IO.File.Exists(source))
				{
					if (sandcastleVersion > importFromSandcastleVersion)
						warnings.Add(Resources.Text.WarningOlderMRefBuilderConfigFileImported);

					try
					{
						System.IO.File.Copy(source, targetMRefBuilderConfigFile, true);
					}
					catch (System.IO.FileNotFoundException) { }
					catch (System.IO.DirectoryNotFoundException) { }
					
					importDefaultMRefBuilderConfig = false;
				}
			}

			if (importDefaultMRefBuilderConfig)
				System.IO.File.Copy(SandcastleBuildEngineProvider.Paths.MRefBuilderConfig, targetMRefBuilderConfigFile, true);

			// Import Build Assembler config files
			ImportAllConfigurationFiles();

			project.GetFolder(config.FullName).Show();
		}

		public void ImportAllConfigurationFiles()
		{
			ImportConfigurationFile(HelpTypes.Help1xReference);
			ImportConfigurationFile(HelpTypes.Help2xReference);
			ImportConfigurationFile(HelpTypes.Help1xConceptual);
			ImportConfigurationFile(HelpTypes.Help2xConceptual);
		}

		public void ImportConfigurationFile(HelpTypes type)
		{
			string sourcePresentation = System.IO.Path.Combine(SandcastleBuildEngineProvider.Paths.Presentation, presentation.Path);
			string targetConfiguration = System.IO.Path.Combine(root, SandcastleBuildEngineProvider.ProjectPaths.Configuration);
			string source, importSource, target;

			switch (type)
			{
				case HelpTypes.Help1xReference:
					source = presentation.ReferenceConfigFile;
					importSource = SandcastleBuildEngineProvider.ProjectPaths.Help1xConfigFileName;
					target = System.IO.Path.Combine(targetConfiguration, importSource);
					break;
				case HelpTypes.Help2xReference:
					source = presentation.ReferenceConfigFile;
					importSource = SandcastleBuildEngineProvider.ProjectPaths.Help2xConfigFileName;
					target = System.IO.Path.Combine(targetConfiguration, importSource);
					break;
				case HelpTypes.Help1xConceptual:
					source = presentation.ConceptualConfigFile;
					importSource = SandcastleBuildEngineProvider.ProjectPaths.Help1xConceptualConfigFileName;
					target = System.IO.Path.Combine(targetConfiguration, importSource);
					break;
				case HelpTypes.Help2xConceptual:
					source = presentation.ConceptualConfigFile;
					importSource = SandcastleBuildEngineProvider.ProjectPaths.Help2xConceptualConfigFileName;
					target = System.IO.Path.Combine(targetConfiguration, importSource);
					break;
				default:
					throw new System.ComponentModel.InvalidEnumArgumentException("type", (int) type, typeof(HelpTypes));
			}

			bool importDefault = true;

			if (importFromSettings != null)
			{
				if (importFromDifferentPresentationStyle)
					warnings.Add(string.Format(System.Globalization.CultureInfo.CurrentCulture,
						Resources.Text.WarningDifferentStyleConfigurationImportFromInstallation, source));
				else if (sandcastleVersion > importFromSandcastleVersion)
					warnings.Add(string.Format(System.Globalization.CultureInfo.CurrentCulture,
						Resources.Text.WarningConfigurationImportFromInstallation, source));
				else
				{
					string importFromSource = System.IO.Path.Combine(System.IO.Path.Combine(
						importFromSettings.TargetDirectory, SandcastleBuildEngineProvider.ProjectPaths.Configuration),
						importSource);

					importDefault = !TryCopyFile(warnings, importFromSource, target, Resources.Errors.CannotImportBuildAssemblerConfigFile, source);
				}
			}

			if (importDefault)
			{
				CreateConfigurationFile(System.IO.File.ReadAllText(System.IO.Path.Combine(sourcePresentation, source)), target, type);
			}
		}

		private void CreateConfigurationFile(string configXml, string configFile, HelpTypes version)
		{
			foreach (ConfigChangeElement change in SandcastleBuildEngineProvider.ConfigChanges)
			{
				if (!string.IsNullOrEmpty(change.Regex)
					&& ((change.Version & version) != 0 || change.Version == HelpTypes.All)
					&& change.PresentationName.Equals("*") || change.PresentationName.Equals(presentation.Name, StringComparison.OrdinalIgnoreCase))
					configXml = change.Apply(configXml);
			}

			XmlDocument document = new XmlDocument();
			document.PreserveWhitespace = true;
			document.LoadXml(configXml);

			foreach (ConfigChangeElement change in SandcastleBuildEngineProvider.ConfigChanges)
			{
				if (!string.IsNullOrEmpty(change.XPath)
					&& ((change.Version & version) != HelpTypes.None || change.Version == HelpTypes.All)
					&& (change.PresentationName.Equals("*") || change.PresentationName.Equals(presentation.Name, StringComparison.OrdinalIgnoreCase)))
					change.Apply(document);
			}

			document.Save(configFile);
		}
		#endregion
	}
}
